package tjs.study.notes.mysql.mybatis.srevice;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import tjs.study.notes.mysql.mybatis.mapper.CmdbTempInstanceLevelMapper;

/**
 * Created by Nicky.Tang on 2023/8/4 09:38
 *
 * @since 02.12.10
 */
@Component
public class TransactionalEventListenerTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(TransactionalEventListenerTest.class);

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private CmdbTempInstanceLevelMapper cmdbTempInstanceLevelMapper;
    @Transactional
    public void testTransactionalEventListener() {
        LOGGER.info("1. 准备新增");
        cmdbTempInstanceLevelMapper.copyIgnore(Long.valueOf(1));
        applicationEventPublisher.publishEvent(new AfterCommitEvent(1));
        LOGGER.info("2. 完成新增");
    }

    /**
     * 1. 注册pplicationListener，监听持有TransactionalEventListener的目标事件
     * {@link org.springframework.transaction.event.TransactionalEventListenerFactory#(java.lang.String, java.lang.Class, java.lang.reflect.Method)}
     *      【new ApplicationListenerMethodTransactionalAdapter(beanName, type, method)】
     *      
     * 2.1 消费目标事件
     * {@link org.springframework.transaction.event.ApplicationListenerMethodTransactionalAdapter#onApplicationEvent(org.springframework.context.ApplicationEvent)}
     * 2.2 将目标方法包装后存入ThreadLocal中
     * {@link org.springframework.transaction.support.TransactionSynchronizationManager#registerSynchronization(org.springframework.transaction.support.TransactionSynchronization)}
     *  ThreadLocal<Set<TransactionSynchronization>> synchronizations
     * {@link org.springframework.transaction.support.TransactionSynchronizationManager#synchronizations}
     * 
     * 3. 事务提交后，从synchronizations取出目标方法，再次执行
     * {@link org.springframework.transaction.support.TransactionSynchronizationUtils#invokeAfterCompletion(java.util.List, int)}
     */
    @TransactionalEventListener
    public void sendToKafka(AfterCommitEvent afterCommitEvent) {
        LOGGER.info("3. 发生到kafka:{}",afterCommitEvent.getSource());
    }


    public static class AfterCommitEvent extends ApplicationEvent {
        
        public AfterCommitEvent(Object source) {
            super(source);
        }
    }
}
